--Finite State Machine 
--有限状态机

local SEPARATOR = '.'
local ANY       = '*'	--任意状状
local ANYSTATE  = ANY .. SEPARATOR 
local ANYEVENT  = SEPARATOR .. ANY
local UNKNOWN   = ANYSTATE .. ANY

local FSM = {}

function FSM.new(...)
	local instance = setmetatable({}, {__index=FSM})
	instance:ctor(...)
	return instance
end

function FSM:ctor(tbState)
	self.state = tbState[1][1]	-- 第一个设为默认状态
	self.stt = {}			-- 事件表 包含 当前状态-要到的状态-回调
	self.str = ""			-- <self.state><SEPARATOR><event> combination
	self.silence = false	-- 默认状态不打印错误

	--初始化为第一个状态
	self.stt[UNKNOWN] = {
		newState = self.state, 
		action = function(...) FSM.exception(self) end
	}
	self:add(tbState)
end
	
--设置当前状态
function FSM:set(s)
	self.state = s 
end

function FSM:get()
	return self.state	
end

function FSM:silent()
	self.silence = true --不输出错误
end

-- 把异常抛出
function FSM:exception() 
	if self.silence == false then 
		print("FSM: unknown combination: " .. self.str)
	end
	return false
end	
	
-- 从当前状态切换到事件对应状态
function FSM:fire(event)
	local act = self.stt[self.state .. SEPARATOR .. event]
	if act==nil then 
		act = self.stt[ANYSTATE .. event]
		if act==nil then
			act = self.stt[self.state .. ANYEVENT]
			if act==nil then
				act = self.stt[UNKNOWN]; 
				self.str = self.state .. SEPARATOR .. event 
			end
		end
	end
	self.state = act.newState	
	return act.action()
end

-- 添加一个状态表
function FSM:add(t)
	for _,v in ipairs(t) do
		local oldState, event, newState, action = v[1], v[2], v[3], v[4]
		self.stt[oldState .. SEPARATOR .. event] = {newState = newState, action = action}
	end
	return #t	-- the requested number of self.state-transitions to be added 
end
	
-- remove self.state transitions from the FSM
function FSM:delete(t)
	for _,v in ipairs(t) do
		local oldState, event = v[1], v[2]
		if oldState == ANY and event == ANY then
			if not self.silence then
				print( "FSM: you should not delete the exception handler" )
				print( "FSM: but assign another exception action" )
			end 
			-- assign default exception handler but stay in current self.state
			self.stt[exception] = {newState = self.state, action = exception}
		else
			self.stt[oldState .. SEPARATOR .. event] = nil
		end
	end
	return #t 	-- the requested number of self.state-transitions to be deleted
end
	
------------------------------------------------------------------
--测试
------------------------------------------------------------------
--[[
local Test = {}
function Test.new(...)
	local instance = setmetatable({}, {__index=Test})
	instance:ctor(...)
	return instance
end
function Test:ctor()
	--状态
	--state1 --eventName --state2 --callback
	self.stateTable = {
		{"rest", 	"to_start", 	"start", 	function() self:onStart() end },
		{"start", 	"to_bet",		"bet", 		function() self:onBet() end },
		{"bet", 	"to_open",		"open", 	function() self:onOpen() end },
		{"*", 		"to_global",	"global", 	function() self:onGlobal() end }, 
		{"global", 	"leave_global",	"*", 		function() self:onLeaveGlobal() end },
		{"*", 		"to_rest",		"rest", 	function() self:onRest() end }, 
	}
	--状态机
	self.fsm = FSM.new(self.stateTable)	
	-- self.fsm:set("rest")
	self.fsm:fire("to_start")	
end
function Test:onStart()
	print("______________start__")
	self.fsm:fire("to_bet")
end
function Test:onBet()
	print("______________bet__")
	self.fsm:fire("to_open")
end
function Test:onOpen()
	print("______________open__")
	self.fsm:fire("to_global")
end
function Test:onGlobal( ... )
	print("___________global___")
	self.fsm:fire("leave_global")
end
function Test:onLeaveGlobal( ... )
	print("__________leave_global___")
	print(self.fsm:get())
	self.fsm:fire("to_rest")
end
function Test:onRest()
	print("______________rest__")
	-- self.fsm:fire("to_bet")
end


local test = Test.new()


--]]


return FSM